
#include <QtOpenGL>

#include "ai/path.h"

Path::Path()
    : m_covered(0)

{
}

Path::Path(const QVector3D& rkStart, const QVector3D& rkEnd)
    : m_covered(0)
{
    append(rkStart);
    append(rkEnd);
}

Path::~Path()
{
}

Path::Path(const Path& rkOther)
    : QLinkedList< QVector3D >(rkOther),
      m_covered(rkOther.m_covered)
{
}

Path& Path::operator = (const Path& rkOther)
{
    // Self assignement.
    if(this == &rkOther)
        return *this;

    clear();
    foreach(const QVector3D& rkVertex, rkOther)
        append(rkVertex);

    m_covered = rkOther.m_covered;

    return *this;
}

bool Path::isValid() const
{
    // A valid path is a path whitch length is greater than one.
    return count() > 1;
}

void Path::paint() const
{
    // Only valid paths can be drawn.
    if(!isValid())
        return;

    glDisable(GL_LIGHTING);
    glPushAttrib(GL_LINE_BIT);
    glPushAttrib(GL_CURRENT_BIT);
    glLineWidth(3.f);
    glBegin(GL_LINES);
    glColor3f(0.7f, 0.7f, 0.2f);

    const float offset = 0.1;

    for(ConstIterator kIt = begin(); kIt + 1 != end(); ++kIt)
    {
        glVertex3f(kIt->x(), kIt->y() + offset, kIt->z());
        glVertex3f((kIt + 1)->x(), (kIt + 1)->y() + offset, (kIt + 1)->z());
    }

    glEnd();
    glPopAttrib();
    glPopAttrib();
    glEnable(GL_LIGHTING);
}

qreal Path::flightLength() const
{
    // Flight length is equal 0 if path is invalid.
    if(!isValid())
        return 0;

    return (last() - first()).length();
}

qreal Path::topologicalLength() const
{
    // Topological length is equal 0 if path is invalid.
    if(!isValid())
        return 0;

    qreal sum = 0;
    for(ConstIterator kIt = begin(); kIt + 1 != end(); ++kIt)
        sum += (*kIt - *(kIt + 1)).length();

    return sum;
}

qreal Path::covered() const
{
    return m_covered;
}

QVector3D Path::position() const
{
    Q_ASSERT(isValid());

    qreal sum = 0;
    for(ConstIterator kIt = begin(); kIt + 1 != end(); ++kIt)
    {
        QVector3D kNext = (*(kIt + 1) - *kIt);
        qreal nextLength = kNext.length();

        if((sum + nextLength) > m_covered)
        {
            qreal t = (m_covered - sum) / nextLength;
            return *kIt + kNext * t;
        }

        sum += nextLength;
    }

    return last();
}

qreal Path::move(qreal length)
{
    // Before path's start.
    if(m_covered + length < 0)
    {
        qreal covered = m_covered;
        m_covered = 0;
        return covered;
    }

    // Exceed path's length.
    qreal total = topologicalLength();
    if(m_covered + length > total)
    {
        qreal covered = total - m_covered;
        m_covered = total;
        return covered;
    }

    // Inside path.
    m_covered += length;
    return length;
}
